<?php

/**
 * JSON 格式化工具，客户端生成
 * 
 * 状态码说明如下：
 *      六位数字，形如 cccbbb（例如 200001，200010，400010），整体可分为两部分
 *      前三位表示操作结果的状态，分大总体状态和具体状态；
 *      后三位描述返回结果的有用字段，也就是要怎么对返回的结果进行处理，
 *          分别对应是否有 “操作” “数据” 和 “消息”，
 *          有为1，无为0，可以将其转换为二进制数来处理。
 * 
 * @example
 * 六位数字，形如 cccbbb（例如 200001，200010，400010），整体可分为两部分
 * 
 * 前三位表示操作结果的状态:
 * [200] 正常
 * [400] 客户端错误
 * [500] 服务器错误
 * 
 * 后三位描述返回结果使用字段:
 * [001] oper可用
 * [010] content可用
 * [100] message可用
 * [011] oper可用 content可用
 * [101] oper可用 message可用
 * [111] oper可用 content可用 message可用
 * 
 * 整体编码举例:
 * [200100] 正常message可用,  message内容为：提交成功
 * [400100] 客户端错误message可用，  message内容为：输入的账户不正确
 * [500100] 服务器端错误message可用， message内容为：无法连接数据库
 *
 * @param int     code    响应状态码
 * @param string  message 响应消息
 * @param object  content 响应内容
 * @param object  oper    操作关键字
 * 
 * @author Jason
 * 
 */
class Lib_json
{
	// Success 200
	const SUCCESS           = 200;
	// Client Error 4xx
	const ERROR_BUSINESS    = 400;
	// Server Error 5xx
	const ERROR_INTERNAL    = 500;
	
	/**
	 * 按接口约定格式向客户端输出一个请求处理发生错误时的JSON串
	 * 
	 * @param int       $code       代码
	 * @param string    $message    消息
	 * @param array     $content    内容
	 * @param array     $oper       操作: 建议包含 operation 和 operand 这两个键
	 * 
	 * @return null 打印出JSON串
	 */
	public static function renderError($code, $message = '', $content = [], $oper = [])
	{
		self::renderType($code, $message, $content, $oper);
	}
	
	/**
	 * 按接口约定格式向客户端输出一个请求正常处理后返回的JSON串
	 * 
	 * @param string    $message    消息
	 * @param array     $content    内容
	 * @param array     $oper       操作: 建议包含 operation 和 operand 这两个键
	 * 
	 * @return null 打印出JSON串
	 */
	public static function renderSuccess($content, $message = '', $oper = [])
	{
		$code = self::SUCCESS;
		self::renderType($code, $message, $content, $oper);
	}
	
	/**
	 * 按接口约定格式向客户端输出一个JSON串
	 *
	 * @param int       $code       代码
	 * @param string    $message    消息
	 * @param array     $content    内容
	 * @param array     $oper       操作: 建议包含 operation 和 operand 这两个键
	 *
	 * @return null 打印出JSON串
	 */
	public static function renderType($code, $message = '', $content = [], $oper = [])
	{
		$arrayResult = array();
		
		$message = self::getMessageText($message);
		
		$arrayResult['code'] = self::calcuteResultCode($code, $message, $content, $oper);
		$arrayResult['message'] = $message;
		$arrayResult['content'] = $content;
		$arrayResult['oper']    = $oper;
		
		self::jsonDisplay($arrayResult);
	}
	
	/**
	 * 直接向客户端输出一个给定数组的JSON串（不建议使用）
	 *
	 * @param array $arrayResult    要转换成JSON串并输出的数组
	 * 
	 * @return null 打印出JSON串
	 */
	public static function renderArray($arrayResult)
	{
		self::jsonDisplay($arrayResult);
	}
	
	/**
	 * 向客户端输出 JSON 数据
	 * 
	 * @param array   $arrayResult
	 * @param boolean $debug
	 */
	private static function jsonDisplay($arrayResult)
	{
		$debug = get_instance()->input->get('debug');
		
		if(!empty($debug)) {
			echo "<pre>";
			echo json_encode($arrayResult, JSON_PRETTY_PRINT);
			echo "\n"; print_r($arrayResult);
			echo "</pre>";
		} else {
			echo json_encode($arrayResult);
		}
	}
	
	/**
	 * 根据数据的空值与否自动计算响应的状态码
	 * 
	 * @param int   $code
	 * @param mixed $message
	 * @param mixed $content
	 * @param mixed $oper
	 * 
	 * @return int
	 */
	private static function calcuteResultCode($code, $message, $content, $oper)
	{
		$subCode = '';
		$subCode .= empty($oper) ? '0' : '1';
		$subCode .= empty($content) ? '0' : '1';
		$subCode .= empty($message) ? '0' : '1';
		
		return intval($code . $subCode);
	}
	
	private static function getMessageText($message)
	{
		$messageText = get_instance()->lang->line($message);
		return $messageText ? $messageText : $message;
	}
	
	public static function getMessageContent($content)
	{
		#$content = array_map(function($item){
		#	return self::getMessageText($item);
		#}, $content);
		array_walk($content, function(&$item){
			$item = self::getMessageText($item);
		});
		return $content;
	}
}
